package edu.hawaii.myisern.model;

import java.io.File;
import java.io.FileWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import edu.hawaii.myisern.organizations.jaxb.AffiliatedResearchers;
import edu.hawaii.myisern.organizations.jaxb.ResearchKeywords;
import edu.hawaii.myisern.organizations.jaxb.Organization;
import edu.hawaii.myisern.organizations.jaxb.Organizations;


/**
 * Wrapper class to handle Organization data.
 * 
 * @author Andrew Wong
 *
 */
public class OrganizationData  implements DisplayableIsernData {

  /**
   * Retrieves the Organizations object stored within.  Used for semantic checking.
   * 
   * @return Instance of Organizations object.
   */
  Organizations getOrganizations() {
    return this.organizations;
  }

  /**
   * Retrieves the data stored in the object.
   * 
   * @return A list of objects in String representation, 
   * entries corresponding to the header entries.
   */
  @Override
  public List<List<String>> getData() {
    List<List<String>> result = new ArrayList<List<String>>();
    
    for (Organization item : this.organizations.getOrganization()) {
      List<String> entry = new ArrayList<String>();
      
      entry.add(MyIsernModel.nullToEmpty(item.getName()));
      entry.add(MyIsernModel.nullToEmpty(item.getType()));
      entry.add(MyIsernModel.nullToEmpty(item.getContact()));

      entry.add(MyIsernModel.nullToEmpty(
          item.getAffiliatedResearchers().getAffiliatedResearcher().toString()));
      entry.add(MyIsernModel.nullToEmpty(item.getCountry()));
      entry.add(MyIsernModel.nullToEmpty(
          item.getResearchKeywords().getResearchKeyword().toString()));

      entry.add(MyIsernModel.nullToEmpty(item.getResearchDescription()));
      entry.add(MyIsernModel.nullToEmpty(item.getHomePage()));
      
      result.add(entry);
    }
   
    return result;
  }
  
  /**
   * Retrieves the field names for the data that is returned.
   * 
   * @return Field names in a list.
   */
  @Override
  public List<String> getHeader() {
    List<String> result = new ArrayList<String>();
    result.add("Name");
    result.add("Type");
    result.add("Contact");
    result.add("Affiliated Researchers");
    result.add("Country");
    result.add("Research Keywords");
    result.add("Research Description");
    result.add("Homepage");

    return result;
  }

  private JAXBContext organizationsJaxbContext;
  private Organizations organizations;

  /**
   * Loads data from XML file.  If baseDir does not exist, it creates
   * an empty data set.
   * 
   * @param baseDir Directory to load data from.
   * @return true if data is loaded successful, false if data load failed.
   */
  public boolean loadData(String baseDir) {
    try {
      // Now do it once more for the researchers. 
      this.organizationsJaxbContext = 
        JAXBContext.newInstance("edu.hawaii.myisern.organizations.jaxb");
      File researchersFile = new File(baseDir + "organizations.xml");
      Unmarshaller unmarshaller = this.organizationsJaxbContext.createUnmarshaller();
      this.organizations = (Organizations) unmarshaller.unmarshal(researchersFile);
    }
    catch (Exception e) {
      Organization foo = new Organization();
      foo.setName(e.toString());
      
      organizations = new Organizations();
      organizations.getOrganization().add(foo);
      
      foo = new Organization();
      foo.setName(baseDir + "/organizations.xml");
      organizations.getOrganization().add(foo);
    }
    
    return true;
  }

  /**
   * Updates or creates the array containing the row that was edited or added.
   * @param newEntry contains the edited/added entry.
   * @param toAdd true if is a new added entry.
   * @return String containing error message, if any.
   */
  @Override
  public String updateData(List<String> newEntry, boolean toAdd) {
    // find the entry first
    Organization target = null;
    AffiliatedResearchers tempAff = new AffiliatedResearchers();
    ResearchKeywords tempKeywords = new ResearchKeywords();

    tempAff.getAffiliatedResearcher();
    tempKeywords.getResearchKeyword();
    
    List<String> tempList;
    
    for (Organization item : this.organizations.getOrganization()) {
      if (newEntry.get(0).trim().equals(item.getName())) {
        target = item;
      }
    }
    
    if (target == null && toAdd) {
      target = new Organization();
      this.organizations.getOrganization().add(target);
    }
    else if (target != null && toAdd) {
      return " Researcher " + newEntry.get(0) + " already exists.";
    }
    else if (target == null && !toAdd) {
      return " Researcher " + newEntry.get(0) + " does not exist, cannot edit.";
    }
    
    //    result.add("Name");
    target.setName(newEntry.get(0).trim());
    
    //    result.add("Organization");
    target.setType(newEntry.get(1).trim());   
    
      
    //    result.add("CollaborationTypes");
    target.setContact(newEntry.get(2).trim());
    
    
    //    result.add("Bio-Statement");
    tempList = MyIsernModel.stringToArray(newEntry.get(3).trim());
    for (String item : tempList) {
      tempAff.getAffiliatedResearcher().add(item);
    }
    target.setAffiliatedResearchers(tempAff);
    
    target.setCountry(newEntry.get(4).trim());
    
    tempList = MyIsernModel.stringToArray(newEntry.get(5).trim());
    for (String item : tempList) {
      tempKeywords.getResearchKeyword().add(item);
    }
    target.setResearchKeywords(tempKeywords);
    
    target.setResearchDescription(newEntry.get(6));
    
    target.setHomePage(newEntry.get(7));

    return "";
  }


  /**
   * Saves data to an XML file.
   * 
   * @param baseDir Directory to save files to.
   * @return true of successful.
   */
  public boolean saveData(String baseDir) {
    Marshaller marshaller;
    try {
      marshaller = this.organizationsJaxbContext.createMarshaller();
      StringWriter writer = new StringWriter();
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT , Boolean.TRUE);
      marshaller.marshal(this.organizations, writer);
      
      FileWriter researcherFile = new FileWriter(baseDir + "organizations.xml");
      researcherFile.write(writer.toString());
      researcherFile.close();


      return true;
    }
    catch (Exception e) {
      e.printStackTrace();
      
      return false;
    }
  }
}
